﻿#region License
// Copyright © 2004 - 2010 All Right Reserved, Derek Goslin
// 
// 1. Definitions
// The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
// A "contribution" is the original software, or any additions or changes to the software.
// A "contributor" is any person that distributes its contribution under this license.
// "Licensed patents" are a contributor's patent claims that read directly on its contribution.
// 
// 2. Grant of Rights
// (A) Copyright Grant- Subject to the terms of this license, including the license
//     conditions and limitations in section 3, each contributor grants you a non-exclusive,
//     worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative 
//     works of its contribution, and distribute its contribution or any derivative works that you create.
// (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations
//     in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its
//     licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of
//     its contribution in the software or derivative works of the contribution in the software.
// 
// 3. Conditions and Limitations
// (A) Reciprocal Grants- For any file you distribute that contains code from the software (in source code or binary format), 
//     you must provide recipients the source code to that file along with a copy of this license, which license will govern that file. 
//     You may license other files that are entirely your own work and do not contain code from the software under any terms you choose.
// (B) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
// (C) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
//     your patent license from such contributor to the software ends automatically.
// (D) If you distribute any portion of the software, you must retain all copyright, patent, trademark,
//     and attribution notices that are present in the software.
// (E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy 
//     of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do 
//     so under a license that complies with this license.
// (F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions.
//    You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your
//    local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
#endregion

using System;
using System.Diagnostics;
using DnEcuDiag.Devices.Exceptions;
using DnEcuDiag.Devices.Responses;
using SerialPort;

namespace DnEcuDiag.Devices
{
    public class Kwp71SerialDevice : Kwp81SerialDevice
    {
        private byte _blockCounter;

        public Kwp71SerialDevice(IPort port, bool disposePort) : base(port, disposePort)
        {
            FrameTitleIndex = 2;
            
        }

        protected override byte[] ReceiveResponse()
        {
            var buffer = new byte[] {};
            Boolean expectedResponse = true;

            if (LastCommand != null)
            {
                if (LastCommand[0] == 0x06)
                {
                    buffer = new byte[] {0, 0, 0x09, 0x03};
                    expectedResponse = false;
                }
            }

            if (expectedResponse)
            {
                byte[] response = WaitForBytes(1, EcuResponseTimeout);
                if (response == null)
                {
                    throw new DeviceTimeoutException("ISO6: Failed to read response byte.", EcuResponseTimeout);
                }

                byte len = response[0];
                buffer = new byte[len];
                buffer[0] = len;

                Port.SendImmediate((byte) (~response[0]));
                WaitForBytes(1, EcuResponseTimeout);

                for (int i = 1; i < len; i++)
                {
                    response = WaitForBytes(1, EcuResponseInterbyteTimeout);
                    if (response == null)
                    {
                        throw new DeviceTimeoutException("ISO8: Failed to read response data bytes.",
                                                         EcuResponseInterbyteTimeout);
                    }

                    Port.SendImmediate((byte) (~response[0]));
                    WaitForBytes(1, EcuResponseTimeout);

                    buffer[i] = response[0];
                }

                response = WaitForBytes(1, EcuResponseInterbyteTimeout);
                if (response == null)
                {
                    throw new DeviceTimeoutException("ISO9: Failed to read response ETX.",
                                                     EcuResponseInterbyteTimeout);
                }

                _blockCounter = ++buffer[1];

                if (EnableTrace)
                {
                    Trace.WriteLine(Response.DumpPacket(buffer));
                }

                if (buffer[FrameTitleIndex] == 0xf6)
                {
                    identificationData.Add(buffer);
                }
            }

            return buffer;
        }

        protected override void TransmitCommand(byte[] commandToSend)
        {
            byte[] response;
            var request = new byte[commandToSend.Length + 2];

            request[0] = (byte) (commandToSend.Length + 2);
            request[1] = _blockCounter;
            Buffer.BlockCopy(commandToSend, 0, request, 2, commandToSend.Length);

            for (int i = 0; i < request.Length; i++)
            {
                Port.SendImmediate(request[i]);
                response = WaitForBytes(1, EcuResponseTimeout);

                response = WaitForBytes(1, 5000);
                if (response == null)
                {
                    throw new DeviceTimeoutException("ISO5: Failed to readback REQUEST message byte.",
                                                     EcuResponseTimeout);
                }
            }

            // Send ETX byte.
            Port.SendImmediate(0x03);
            response = WaitForBytes(1, EcuResponseTimeout);
            if (response == null)
            {
                throw new DeviceTimeoutException("ISO5: Failed to readback ETX echo.", EcuResponseTimeout);
            }
        }

    }
}